/*******************************************************************************
  MPLAB Harmony Application Source File
  
  Company:
    Microchip Technology Inc.
  
  File Name:
    app.c

  Summary:
    This file contains the source code for the MPLAB Harmony application.

  Description:
    This file contains the source code for the MPLAB Harmony application.  It 
    implements the logic of the application's state machine and it may call 
    API routines of other MPLAB Harmony modules in the system, such as drivers,
    system services, and middleware.  However, it does not call any of the
    system interfaces (such as the "Initialize" and "Tasks" functions) of any of
    the modules in the system or make any assumptions about when those functions
    are called.  That is the responsibility of the configuration-specific system
    files.
 *******************************************************************************/

// DOM-IGNORE-BEGIN
/*******************************************************************************
Copyright (c) 2013-2014 released Microchip Technology Inc.  All rights reserved.

Microchip licenses to you the right to use, modify, copy and distribute
Software only when embedded on a Microchip microcontroller or digital signal
controller that is integrated into your product or third party product
(pursuant to the sublicense terms in the accompanying license agreement).

You should refer to the license agreement accompanying this Software for
additional information regarding your rights and obligations.

SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF
MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER
CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR
OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR
CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF
SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
(INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
 *******************************************************************************/
// DOM-IGNORE-END


// *****************************************************************************
// *****************************************************************************
// Section: Included Files 
// *****************************************************************************
// *****************************************************************************

#include "app.h"
#include "pcf8575.h"
#include "ad5620.h"
#include "user_config.h"

// *****************************************************************************
// *****************************************************************************
// Section: Global Data Definitions
// *****************************************************************************
// *****************************************************************************

// *****************************************************************************
/* Application Data

  Summary:
    Holds application data

  Description:
    This structure holds the application's data.

  Remarks:
    This structure should be initialized by the APP_Initialize function.
    
    Application strings and buffers are be defined outside this structure.
*/

APP_DATA appData;

// *****************************************************************************
// *****************************************************************************
// Section: Application Callback Functions
// *****************************************************************************
// *****************************************************************************

/* TODO:  Add any necessary callback funtions.
*/

// *****************************************************************************
// *****************************************************************************
// Section: Application Local Functions
// *****************************************************************************
// *****************************************************************************

/* TODO:  Add any necessary local functions.
*/

uint8_t TestMessage[8]; //Test message to transmit on CAN
uint8_t can_send_buff[20];
extern OS_SEM   can0_recv_sem;
CAN_RX_MSG_BUFFER can1_recv_data;

extern uint8_t well_open_flag;
extern uint8_t well_shut_flag;
extern OS_SEM   well_ctrl_sem;

extern uint16_t set_freq_value; //需要调整到的频率值。 
extern OS_SEM   freq_ctrl_sem; //远程控制AO输出信号量。 

extern void save_cfg_para(uint8_t reset_flag);
/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  read_all_mes_tbl
 *  Description:  读取所有测量信息表
 * =====================================================================================
 */
void read_all_mes_tbl(uint8_t master_addr){

	uint8_t i;
	uint8_t j;
	uint16_t n_sid = 0;  //非结束帧SID
	uint16_t l_sid = 0;  //结束帧的SID
	uint16_t mes_tbl_size = 64;
	uint16_t slave_addr = cfg_tbl[CFG_OFS_DEV_ADDR];
	uint8_t send_times;
	uint8_t last_frame_size;
	OS_ERR os_err;

	n_sid = (((slave_addr << 3) & 0x03f8) | 0x0403);
	l_sid = (((slave_addr << 3) & 0x03f8) | 0x0402);

	if(mes_tbl_size % 3 == 0){
		send_times = mes_tbl_size/3;
		last_frame_size = 3;
	}else{
		send_times = mes_tbl_size/3 + 1;
		last_frame_size = mes_tbl_size % 3;
	}

	for ( i = 0; i < send_times; i += 1 ) {
		TestMessage[0] = master_addr; 						/*从站地址*/ 
		TestMessage[1] = i;                                                     /*帧序号*/
		if(i == (send_times - 1)){ /*最后一帧*/ 
			for ( j = 0; j < last_frame_size; j += 1 ) {
				TestMessage[2 + j*2] = (mes_tbl[i*3 + j] >> 8) & 0x00ff; 		/*数据*/
				TestMessage[2 + j*2 + 1] = (mes_tbl[i*3 + j] >> 0)& 0x00ff; 	/*数据*/
			}
                        pcf8575_led_toggle(LED_HI_07);     //发送LED。
                        DRV_CAN0_ChannelMessageTransmit(CAN_CHANNEL0, l_sid, last_frame_size*2 + 2, &TestMessage[0]);
		}else{ /*非结束帧*/ 
			for ( j = 0; j < 3; j += 1 ) {
				TestMessage[2 + j*2] = (mes_tbl[i*3 + j] >> 8) & 0x00ff; 		/*数据*/
				TestMessage[2 + j*2 + 1] = (mes_tbl[i*3 + j] >> 0)& 0x00ff; 	/*数据*/
			}
                        pcf8575_led_toggle(LED_HI_07);     //发送LED。
                        DRV_CAN0_ChannelMessageTransmit(CAN_CHANNEL0, n_sid, 8, &TestMessage[0]);
		}
		OSTimeDly (100, OS_OPT_TIME_DLY, &os_err);
	}
	return ;
}		/* -----  end of function read_all_mes_tbl  ----- */

/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  read_all_cfg_tbl
 *  Description:  
 * =====================================================================================
 */
void read_all_cfg_tbl(uint8_t master_addr){

	uint8_t i;
	uint8_t j;
	uint16_t n_sid = 0;  //非结束帧SID
	uint16_t l_sid = 0;  //结束帧的SID
	uint16_t mes_tbl_size = 64;
	uint16_t slave_addr = cfg_tbl[CFG_OFS_DEV_ADDR];
	uint8_t send_times;
	uint8_t last_frame_size;
	OS_ERR os_err;

	n_sid = (((slave_addr << 3) & 0x03f8) | 0x0403);
	l_sid = (((slave_addr << 3) & 0x03f8) | 0x0402);

	if(mes_tbl_size % 3 == 0){
		send_times = mes_tbl_size/3;
		last_frame_size = 3;
	}else{
		send_times = mes_tbl_size/3 + 1;
		last_frame_size = mes_tbl_size % 3;
	}

	for ( i = 0; i < send_times; i += 1 ) {
		TestMessage[0] = master_addr; 						/*从站地址*/ 
		TestMessage[1] = i;                                                     /*帧序号*/
		if(i == (send_times - 1)){ /*最后一帧*/ 
			for ( j = 0; j < last_frame_size; j += 1 ) {
				TestMessage[2 + j*2] = (cfg_tbl[i*3 + j] >> 8) & 0x00ff; 		/*数据*/
				TestMessage[2 + j*2 + 1] = (cfg_tbl[i*3 + j] >> 0)& 0x00ff; 	/*数据*/
			}
                        pcf8575_led_toggle(LED_HI_07);     //发送LED。
                        DRV_CAN0_ChannelMessageTransmit(CAN_CHANNEL0, l_sid, last_frame_size*2 + 2, &TestMessage[0]);
		}else{ /*非结束帧*/ 
			for ( j = 0; j < 3; j += 1 ) {
				TestMessage[2 + j*2] = (cfg_tbl[i*3 + j] >> 8) & 0x00ff; 		/*数据*/
				TestMessage[2 + j*2 + 1] = (cfg_tbl[i*3 + j] >> 0)& 0x00ff; 	/*数据*/
			}
                        pcf8575_led_toggle(LED_HI_07);     //发送LED。
                        DRV_CAN0_ChannelMessageTransmit(CAN_CHANNEL0, n_sid, 8, &TestMessage[0]);
		}
		OSTimeDly (100, OS_OPT_TIME_DLY, &os_err);
	}
	return ;
}		/* -----  end of function read_all_cfg_tbl  ----- */

/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  ctl_well_open
 *  Description:  远程控制启动油井运行
 * =====================================================================================
 */
void ctl_well_open(uint8_t master_addr){

    uint16_t slave_addr = cfg_tbl[CFG_OFS_DEV_ADDR];
	uint16_t l_sid = (((slave_addr << 3) & 0x03f8) | 0x0401);


	TestMessage[0] = master_addr;  /*主站地址*/
	TestMessage[1] = 0x03;        /*功能码*/
	TestMessage[2] = 0x10;
	TestMessage[3] = 0x00;
	TestMessage[4] = 0xFF;  
	TestMessage[5] = 0x00;  

	pcf8575_led_toggle(LED_HI_07);     //发送LED。
	DRV_CAN0_ChannelMessageTransmit(CAN_CHANNEL0, l_sid, 6, &TestMessage[0]);
        well_open_flag = 1;
        OSAL_SEM_Post(&well_ctrl_sem); /*发送接收完成的信号量*/
	return ;
}		/* -----  end of function ctl_well_open  ----- */

/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  ctl_well_shut
 *  Description:  远程控制停止油井运行
 * =====================================================================================
 */
void ctl_well_shut(uint8_t master_addr){

    uint16_t slave_addr = cfg_tbl[CFG_OFS_DEV_ADDR];
	uint16_t l_sid = (((slave_addr << 3) & 0x03f8) | 0x0401);

	TestMessage[0] = master_addr;  /*主站地址*/
	TestMessage[1] = 0x03;        /*功能码*/
	TestMessage[2] = 0x10;
	TestMessage[3] = 0x00;
	TestMessage[4] = 0x00;  
	TestMessage[5] = 0x00;  

	pcf8575_led_toggle(LED_HI_07);     //发送LED。
	DRV_CAN0_ChannelMessageTransmit(CAN_CHANNEL0, l_sid, 6, &TestMessage[0]);
        well_shut_flag = 1;
        OSAL_SEM_Post(&well_ctrl_sem); /*发送接收完成的信号量*/
	return ;
}		/* -----  end of function ctl_well_shut  ----- */

/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  ctl_well_freq
 *  Description:  远程控制调整频率
 * =====================================================================================
 */
void ctl_well_freq(uint8_t master_addr, uint16_t freq){

        uint16_t temp = 0;
    	uint16_t slave_addr = cfg_tbl[CFG_OFS_DEV_ADDR];
	uint16_t l_sid = (((slave_addr << 3) & 0x03f8) | 0x0401);


	TestMessage[0] = master_addr;  /*从站地址*/
	TestMessage[1] = 0x03;        /*功能码*/
	TestMessage[2] = 0x10;
	TestMessage[3] = 0x01;
	TestMessage[4] = (freq >> 8) & 0x00ff;  
	TestMessage[5] = (freq >> 0) & 0x00ff;  

	pcf8575_led_toggle(LED_HI_07);     //发送LED。
	DRV_CAN0_ChannelMessageTransmit(CAN_CHANNEL0, l_sid, 6, &TestMessage[0]);

	if((freq >= 0) && (freq <= 5000)){
		set_freq_value = freq;
		OSAL_SEM_Post(&freq_ctrl_sem); /*发送接收完成的信号量*/
	}
	return ;
}		/* -----  end of function ctl_well_freq  ----- */

/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  can_recv_analy
 *  Description:  解析CAN接收到的数据。
 * =====================================================================================
 */
void can_recv_analy(void){

	uint8_t type;
	uint8_t master_addr;
	uint16_t ctl_code_1;
	uint16_t ctl_code_2;
	uint16_t sid = can1_recv_data.msgSID.sid;

	ctl_code_1 = can1_recv_data.data[2];
	ctl_code_1 = ((ctl_code_1 << 8) & 0xff00) + can1_recv_data.data[3];

	ctl_code_2 = can1_recv_data.data[4];
	ctl_code_2 = ((ctl_code_2 << 8) & 0xff00) + can1_recv_data.data[5];

	type = (sid & 0x0007);
	master_addr = (((sid & 0xfff8) >> 3) & 0x7f);

	if(can1_recv_data.data[0] != 0x02){ /*判断从站地址*/ 

	}else{

	}

	switch(can1_recv_data.data[1]){
		case 0x01:	 /*主站请求全部测量信息*/ 
			if(cfg_tbl[CFG_OFS_CAN_DEBUG_LEVEL] >= 1){
				PLIB_PORTS_PinSet(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
				printf("RTU read all mes table!\r\n");
				PLIB_PORTS_PinClear(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
			}
			read_all_mes_tbl(master_addr);
			break;
		case 0x02:	 /*主站请求全部配置信息*/ 
			if(cfg_tbl[CFG_OFS_CAN_DEBUG_LEVEL] >= 1){
				PLIB_PORTS_PinSet(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
				printf("RTU read all ctl table!\r\n");
				PLIB_PORTS_PinClear(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
			}

			read_all_cfg_tbl(master_addr);
			break;
		case 0x03:	 /*主站控制信息*/ 
			if(ctl_code_1 == 0x1000){ /*控制启停井*/ 
				if(ctl_code_2 == 0xff00){ /*远程控制起井*/ 
					if(cfg_tbl[CFG_OFS_CAN_DEBUG_LEVEL] >= 1){
						PLIB_PORTS_PinSet(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
						printf("RTU control well open!\r\n");
						PLIB_PORTS_PinClear(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
					}
					ctl_well_open(master_addr);
				}
				if(ctl_code_2 == 0x0000){ /*远程控制停井*/ 
					if(cfg_tbl[CFG_OFS_CAN_DEBUG_LEVEL] >= 1){
						PLIB_PORTS_PinSet(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
						printf("RTU control well shut!\r\n");
						PLIB_PORTS_PinClear(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
					}
					ctl_well_shut(master_addr);
				}
			}
			if(ctl_code_1 == 0x1001){ /*远程调频*/ 
				if(cfg_tbl[CFG_OFS_CAN_DEBUG_LEVEL] >= 1){
					PLIB_PORTS_PinSet(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
					printf("RTU change well frequency! freq = [%d]\r\n", ctl_code_2);
					PLIB_PORTS_PinClear(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
				}
				ctl_well_freq(master_addr, ctl_code_2);
			}
			break;
		default:	
			break;
	}				/* -----  end switch  ----- */
	return ;
}		/* -----  end of function can_recv_analy  ----- */

// *****************************************************************************
// *****************************************************************************
// Section: Application Initialization and State Machine Functions
// *****************************************************************************
// *****************************************************************************

/*******************************************************************************
  Function:
    void APP_Initialize ( void )

  Remarks:
    See prototype in app.h.
 */

void APP_Initialize ( void )
{
	/* Place the App state machine in its initial state. */
	appData.state = APP_STATE_INIT;

	/* TODO: Initialize your application's state machine and other
	 * parameters.
	 *
	 */

//	/*setup rtos tick interrupt source, for 1ms tick*/
//	__builtin_mtc0(11,0,100000);
//	/*start counting from zero*/
//	__builtin_mtc0(9,0,0);
//	/*clear interrupt flag, before enabling*/
//	PLIB_INT_SourceFlagClear(INT_ID_0,INT_SOURCE_TIMER_CORE);
//	/*enable interrupt source and set IPL for core timer*/
//	PLIB_INT_VectorPrioritySet(INT_ID_0,INT_VECTOR_CT,INT_PRIORITY_LEVEL2);
//	PLIB_INT_SourceEnable(INT_ID_0,INT_SOURCE_TIMER_CORE);

}

/******************************************************************************
  Function:
    void APP_Tasks ( void )

  Remarks:
    See prototype in app.h.
 */

void APP_Tasks ( void )
{
      uint8_t ret;
      uint16_t i;
  
    /* Check the application's current state. */
    switch ( appData.state )
    {
	    /* Application's initial state. */
	    case APP_STATE_INIT:
		    {
			    ret = OSAL_SEM_Pend(&can0_recv_sem, 0);		/*等待接收的信号量*/
			    if(ret == DEF_OK){        //接收到数据
				    if(cfg_tbl[CFG_OFS_CAN_DEBUG_LEVEL] >= 2){
					    PLIB_PORTS_PinSet(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
					    printf("CAN Recv:");
					    for (i = 0; i < can1_recv_data.msgEID.data_length_code; i++)
						    printf("[%.2X]", can1_recv_data.data[i]);
					    printf("\n");
					    PLIB_PORTS_PinClear(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
				    }
				    pcf8575_led_toggle(LED_HI_08);     //点亮接收LED。
				    can_recv_analy();
			    }else{

			    }
			    break;
		    }

		    /* TODO: implement your application state machine.*/


		    /* The default state should never be executed. */
	    default:
		    {
			    /* TODO: Handle error in application's state machine. */
			    break;
		    }
    }
}
 

/*******************************************************************************
 End of File
 */
